#include "sphere.h"

#include "geometry/ray.h"
#include "geometry/diff_geometry.h"

namespace venus {
/******************The Ray-Sphere Intersection Algorithm*****************
 * 1. the direction of ray is assumed to have been normalized, so
 * 2. |b| is the projected length of v to ray
 * 3. sqrt(Dot(v, v) - (b * b)) is the distance from sphere center to the ray
 * 4. there'll be no intersection if the distance from sphere center to ray 
 *    is bigger than sphere radius, the det is for the judgement,
 *    and if det > 0, sqrt(det) is half the length of the cord cut by the ray
 * 5. calculate the two intersection point, and check whether they are in the
 *    range of the ray
 ************************************************************************/
int Sphere::Intersect(const Ray &ray) const {
  const Vector3 &v = center_ - ray.o;
  const float b = Dot(v, ray.d);
  const float det = (b * b) - Dot(v, v) + Math::square(radius_);
  if (det < 0) return MISS;
  const float half_cord_length = sqrt(det);
  const float tfar = b + half_cord_length;
  if (tfar < ray.tmin) return MISS;
  const float tnear = b - half_cord_length;
  if (tnear > ray.tmax) return MISS;
  return HIT;
}

int Sphere::Intersect(const Ray& ray, float *thit, 
    DifferentialGeometry *dg) const {
  const Vector3 &v = center_ - ray.o;
  const float b = Dot(v, ray.d);
  const float det = (b * b) - Dot(v, v) + Math::square(radius_);
  if (det < 0) return MISS;
  const float half_cord_length = sqrt(det);
  const float tfar = b + half_cord_length;
  if (tfar < ray.tmin) return MISS;
  const float tnear = b - half_cord_length;
  if (tnear > ray.tmax) return MISS;
  float t = tnear;
  if (t < ray.tmin) {
    t = tfar;
    if (t > ray.tmax) return MISS;
  }
  *thit = t;
  /***************************************************
   * compute for DifferentialGeometry
   **************************************************/


  return HIT;
}

}//namespace venus
